package com.abing.starry.service.impl;

import cn.hutool.json.JSONUtil;
import com.abing.api.model.StarryApiRequest;
import com.abing.starry.common.ErrorCode;
import com.abing.starry.exception.BusinessException;
import com.abing.starry.exception.ThrowUtils;
import com.abing.starry.mapper.InterfaceInfoMapper;
import com.abing.starry.model.dto.interfaces.InvokeCountDTO;
import com.abing.starry.model.entity.InterfaceInfoEntity;
import com.abing.starry.model.entity.UserEntity;
import com.abing.starry.model.entity.UserInterfaceInfoEntity;
import com.abing.starry.model.enums.InterfaceApplyEnum;
import com.abing.starry.model.enums.InterfaceStatusEnum;
import com.abing.starry.model.request.interfaces.QueryCountRequest;
import com.abing.starry.model.request.interfaces.QueryInterfaceRequest;
import com.abing.starry.model.vo.InterfaceInfoVO;
import com.abing.starry.service.InterfaceInfoService;
import com.abing.starry.service.UserInterfaceInfoService;
import com.abing.starry.strategy.api.InvokeStrategyExecutor;
import com.abing.starry.util.TokenUtils;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.abing.starry.constant.RedisKeyConstant.INTERFACE_COUNT_DAY;

/**
 * @author 阿炳亿点点帅
 * @description 针对表【interface_info(接口信息)】的数据库操作Service实现
 * @createDate 2024-08-23 15:16:51
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class InterfaceInfoServiceImpl extends ServiceImpl<InterfaceInfoMapper, InterfaceInfoEntity>
        implements InterfaceInfoService {

    private final InvokeStrategyExecutor invokeStrategyExecutor;

    private final InterfaceInfoMapper interfaceInfoMapper;

    private final UserInterfaceInfoService userInterfaceInfoService;

    private final StringRedisTemplate stringRedisTemplate;

    @Override
    public String apiInvoke(StarryApiRequest starryApiRequest) {

        // TODO 采用缓存
        List<InterfaceInfoEntity> interfaceInfoEntityList = this.list();
        boolean isStarryApi = interfaceInfoEntityList.stream()
                                                     .map(InterfaceInfoEntity::getUrl)
                                                     .anyMatch(baseUrl -> StringUtils.contains(baseUrl, starryApiRequest.getUrl()));

        return invokeStrategyExecutor.doInvoke(starryApiRequest, isStarryApi);
    }

    @Override
    public IPage<InterfaceInfoEntity> queryInterfaceByPage(QueryInterfaceRequest queryInterfaceRequest) {

        return this.page(new Page<>(queryInterfaceRequest.getCurrent(), queryInterfaceRequest.getPageSize()),
                         Wrappers.lambdaQuery(InterfaceInfoEntity.class)
                                 .like(StringUtils.isNotEmpty(queryInterfaceRequest.getName()), InterfaceInfoEntity::getName, queryInterfaceRequest.getName())
                                 .like(StringUtils.isNotEmpty(queryInterfaceRequest.getDescription()), InterfaceInfoEntity::getUrl, queryInterfaceRequest.getDescription())
                                 .eq(StringUtils.isNotEmpty(queryInterfaceRequest.getMethod()), InterfaceInfoEntity::getStatus, queryInterfaceRequest.getMethod()));
    }


    @Override
    public IPage<InterfaceInfoVO> queryInvokeCountByPage(QueryCountRequest queryCountRequest) {


        UserEntity currentUser = TokenUtils.getCurrentUser();
        String userId = currentUser.getId();
        String type = queryCountRequest.getType();
        userId = InterfaceApplyEnum.APPlY.name().equalsIgnoreCase(type) ? userId : null;

        Page<InvokeCountDTO> page = new Page<>(queryCountRequest.getCurrent(), queryCountRequest.getPageSize());
        IPage<InvokeCountDTO> invokeCountPage = interfaceInfoMapper.queryInvokeCount(page, queryCountRequest.getName(), userId);
        List<InvokeCountDTO> records = invokeCountPage.getRecords();

        List<Object> interfaceIdList = records.stream().map(InvokeCountDTO::getId).collect(Collectors.toList());
        List<Object> countList = stringRedisTemplate.opsForHash().multiGet(INTERFACE_COUNT_DAY, interfaceIdList);

        List<InterfaceInfoVO> interfaceInfoVOList = records
                .stream()
                .map(interfaceDTO -> {
                    InterfaceInfoVO interfaceInfoVO = new InterfaceInfoVO();
                    List<String> applyUserList = JSONUtil.toList(interfaceDTO.getApplyUser(), String.class);
                    boolean isApply = applyUserList.stream()
                                                   .anyMatch(u -> u.equals(TokenUtils.getCurrentUser().getId()));
                    interfaceInfoVO.setInvokeTotal(Objects.nonNull(interfaceDTO.getInvokeCountSum()) ? interfaceDTO.getInvokeCountSum() : 0L);
                    interfaceInfoVO.setStatus(interfaceDTO.getStatus());
                    interfaceInfoVO.setIsApply(isApply);
                    interfaceInfoVO.setId(interfaceDTO.getId());
                    interfaceInfoVO.setName(interfaceDTO.getName());
                    interfaceInfoVO.setDescription(interfaceDTO.getDescription());
                    return interfaceInfoVO;
                }).collect(Collectors.toList());

        for (int i = 0; i < interfaceInfoVOList.size(); i++) {
            InterfaceInfoVO interfaceInfoVO = interfaceInfoVOList.get(i);
            Object countObj = countList.get(i);
            long dayCount = Objects.nonNull(countObj) ? Long.parseLong(countObj.toString()) : 0L;
            interfaceInfoVO.setInvokeDayTotal(dayCount);
        }

        IPage<InterfaceInfoVO> interfaceInfoVOPage = new Page<>();
        BeanUtils.copyProperties(invokeCountPage, interfaceInfoVOPage);
        interfaceInfoVOPage.setRecords(interfaceInfoVOList);
        return interfaceInfoVOPage;
    }

    @Override
    public boolean applyInterface(String id, Boolean isAgree) {

        ThrowUtils.throwIf(!isAgree, ErrorCode.OPERATION_ERROR, "用户未同意API使用协议");
        String userId = TokenUtils.getCurrentUser().getId();

        InterfaceInfoEntity interfaceInfoEntity = this.getById(id);

        if (InterfaceStatusEnum.OFF.getStatus().equals(interfaceInfoEntity.getStatus())) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "接口已关闭,无法申请");
        }

        String applyUser = interfaceInfoEntity.getApplyUser();
        List<String> applyUserList = JSONUtil.toList(applyUser, String.class);
        applyUserList.add(userId);
        interfaceInfoEntity.setApplyUser(JSONUtil.toJsonStr(applyUserList));
        ThrowUtils.throwIf(!this.updateById(interfaceInfoEntity), ErrorCode.OPERATION_ERROR);

        UserInterfaceInfoEntity userInterfaceInfoEntity = userInterfaceInfoService.getOne(
                Wrappers.lambdaQuery(UserInterfaceInfoEntity.class)
                        .eq(UserInterfaceInfoEntity::getUserId, userId)
                        .eq(UserInterfaceInfoEntity::getInterfaceId, id));
        if (Objects.nonNull(userInterfaceInfoEntity)) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "请勿重复申请");
        }
        UserInterfaceInfoEntity saveUserInterface = new UserInterfaceInfoEntity();
        saveUserInterface.setUserId(userId);
        saveUserInterface.setInterfaceId(id);
        ThrowUtils.throwIf(!userInterfaceInfoService.save(saveUserInterface), ErrorCode.OPERATION_ERROR);



        return true;
    }

    @Override
    public boolean saveInterface(InterfaceInfoEntity interfaceInfoEntity) {

        String id = TokenUtils.getCurrentUser().getId();
        interfaceInfoEntity.setUserId(id);
        boolean saveStatus = this.save(interfaceInfoEntity);
        ThrowUtils.throwIf(!saveStatus,ErrorCode.OPERATION_ERROR);

        return true;
    }
}




